module necrophilia.animation.Base;
import utils.Memory;
import maths.CoordSys;

/**
	Simplest keyframe. As in definition the keyframe is implemented as a point in time (where Time type is free to set as it is a template)
	where the bone is transformed by translating and rotating it. The translation vector and rotation quaternion are held in maths.CoordSys
*/
struct Keyframe(Time){
	Time time; /// point in time
	CoordSys transformation; /// translation and rotation
}


/**
	Animation. Animaiton is a set of keyframes for each bone, with it's speed (how fast the time is going) , and it's starting point. Why starting point ? First for
	flexibility. Some people meybe would like to start their animations in half of the keyframes. Second - for more flexibility. if i would decide
	to set start to 0... the Time type would have to know what 0 is.. i don't want to do such a restrictions. It's programmer's job to tell wherefrom
	starting the animation.
	Note:
	All the memory is allocated manually, without knowlage of the gc, it is cleaned in Animation class destructor
*/
class Animation(Time){
	private Keyframe!(Time)[][] _keyframes;
	private Time _speed;
	private Time _start;
	char[] name;
	package bool isCalculated;
	package CoordSys[] firstNested;
	
	/** 
			Constructior
			Params:
			n = number of bones. As it was mentioned - animation holds keyframes per bone
			speed = animations speed. This speed is later used to create Timer in AnimationInstance
			start = the start point, in most cases it would be a 0 for you, but i don't set it as a default for the reason i've mentioned;
	*/
	this(int n, Time speed, Time start){
		_keyframes.alloc(n);
		_speed=speed;
		_start=start;
		isCalculated=false;
	}
	
	this(char[] name, int n, Time speed, Time start){
		this(n,speed,start);
		this.name=name.dup;
		firstNested.alloc(bonesNumber);
	}
	
	~this(){
		foreach(inout keyframes;_keyframes){
			if(keyframes.length>0) keyframes.free();
		}
		_keyframes.free();
		firstNested.free();
	}
	
	/** 
			Method used for building the animation keyframes
			Params:
			boneIndex=index of a bone, for which the keyframe is for (transformation of the bone should occur)
			time= the time of the keyframe
			transformation= keyframes transformation
	*/
	void addKeyframe (int boneIndex, Time time, CoordSys transformation){
		_keyframes[boneIndex].realloc(_keyframes[boneIndex].length+1);
		Keyframe!(Time) *keyframe=&_keyframes[boneIndex][_keyframes[boneIndex].length-1];
		keyframe.time=time;
		keyframe.transformation=transformation;
		//writefln(boneIndex," ",transformation.origin);
		//getchar();
		/*_keyframes[boneIndex].length=_keyframes[boneIndex].length+1;
		_keyframes[boneIndex][_keyframes[boneIndex].length-1].time=time;
		_keyframes[boneIndex][_keyframes[boneIndex].length-1].transformation=transformation;*/
	}
	
	/**
			Will give keyframes for apropriate bone
			Params:
			boneIndex= index of a bone you want to get keyframe set
			Returns:
			keyframset
	*/
	Keyframe!(Time)[] keyframes(int boneIndex){
		return _keyframes[boneIndex];
	}
	
	/* 
		Two next methods are for geting infpormations about the informations. Set metods are not provided 
		because it would be to dengeraus. Seting something here would heve effect on all objects useing that animation
		whitch would heve nosense
		Returns
		animation speed in first
		animation start point in second
		animation supported bone quantity in third
	*/	
	Time speed()
	{
		return _speed;
	}
	
	/// ditto
	Time start(){
		return _start;
	}
	
	/// ditto
	int bonesNumber(){
		return _keyframes.length;
	}
}
	
import std.stdio;